﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClusterAggregation.Datum
{
    /**
     * Abstract datum form.
     * Generalizes the coordinates to be whatever we need, color, location, a vector etc.
     */
    public class AData
    {
        /** singular id (assigned by creator of object) */
        public Int32 id ;
        /** coordinates vector */
        public double[] coordinates;
        /** static random number generator */
        static private Random randomizer = new Random();

        /** most basic comparator, by id */
        virtual public int compareTo(AData obj)
        {
            if (obj.id == id)
                return 0;
            if (obj.id > id)
                return -1;
            return 1;
        }
        /** generates a new RANDOM datum */
        virtual public AData getRandomDatum()
        {
            AData tmp = new AData(coordinates.Length);
            for (int i = 0; i < coordinates.Length; i++)
            {
                tmp.coordinates[i] = randomizer.NextDouble() * 1000;
            }
            tmp.id = -1;
            return tmp;
        }
        /** 
         * normalize the coordinates (divides by param)
         * @param arg (int) [IN]
         */
        virtual public void normalize(int arg)
        {
            for (int i = 0; i < coordinates.Length; i++)
                coordinates[i] = (Int16)(coordinates[i] / arg);
        }

        /**
         * accumulates another data into current datum.
         * only accumulates a part of it (e.g. arg.x / totalDataNumber)
         * @param arg (AData) [IN] the data to accumulate
         * @param totalDataNumber (int) [IN] the total number of data we're going to accumulate.
         */
        virtual public void accumulate(AData arg,int totalDataNumber)
        {
            double tmp;
            for (int i = 0; i < coordinates.Length; i++)
            {
                if (totalDataNumber == 0)
                {
                    tmp = (arg.coordinates[i] * (randomizer.NextDouble() > 0.5 ? 0.99 : 1.01));
                }
                else
                    if (double.IsNaN(arg.coordinates[i]))
                        tmp = 0;
                    else
                        tmp = (arg.coordinates[i] / totalDataNumber);
                coordinates[i] += tmp;
            }
        }

        /**
         * function resets all the coordinates. thus we can later accumulate data inside and calculate a new point (for k-means and such).
         */
        virtual public void zerodize()
        {
            for (int i = 0; i < coordinates.Length; i++)
                coordinates[i] = 0;
        }

        /**
         * constructor.
         * @param dimension (int) [IN] sets the dimension of the coordinates vector.
         */
        public AData(int dimension = 0)
        {
            coordinates = new double[dimension];
            id = 0;
        }



    }
}
